package comms

import (
	"ewdetect/config"
	"ewdetect/detect"
	"ewdetect/events"
	"ewdetect/stations"
	"ewdetect/utils"
	"time"

	"github.com/GeoNet/kit/seis/ms"
	"github.com/GeoNet/kit/seis/sl"
	"github.com/rs/zerolog/log"
)

var Connections = make(map[string]*Connection)

type Connection struct {
	Buffers   *map[string]*[config.BufferSize]int32
	Heads     *map[string]int
	HeadLoops *map[string]int
	StartTime *time.Time
}

// https://github.com/GeoNet/kit/blob/main/shake/intensity.go
func StreamThread(url string) {
	log.Info().Str("url", url).Msg("Connecting to stream")
	var buffers = make(map[string]*[config.BufferSize]int32)
	var heads = make(map[string]int)
	var headLoops = make(map[string]int)
	var startTime = time.Now()

	Connections[url] = &Connection{&buffers, &heads, &headLoops, &startTime}
	/*conn, err := sl.NewConn(url, 5*time.Second)
	utils.CheckError(err)
	defer conn.Close()

	info, err := conn.GetInfo("streams") // stations also possible
	utils.CheckError(err)

	stations := info.Station
	for _, station := range stations {
		fmt.Println("Found", station.Name, "-", station.Description)
		//fmt.Println(station.Stream)
	}*/

	sdl := sl.NewSLink(
		sl.SetServer(url),
		sl.SetTimeout(5*time.Second),
		sl.SetKeepAlive(30*time.Second),
		sl.SetStreams("*"),
		sl.SetSelectors("EHZ"), // Short Period - Identified in seismograms with the suffix "EHZ" - sensitive velocity seismometers with a response peaked around 1 Hz. Typically only a single vertical component. Primarily used for determination of locations and magnitudes of small regional earthquakes. Strong Motion - Identified in seismograms by suffixes: "ENZ" or "HNZ" (Vertical), "ENE" or "HNE" (East-West horizontal), and "ENN" or "HNN" (North-South horizontal) - accelerometers with three components. Designed to record on-scale waveforms from moderate and large regional earthquakes that give rise to strong shaking. Broadband - Identified in seismograms by suffixes: "BHZ" or "HHZ" (Vertical), "BHE" or "HHE" (East-West horizontal), or "BHN" or "HHN" (North-South horizontal - velocity seismometers with a wide frequency response. Primary purpose is to record waveforms from regional and distant earthquakes for research purposes.

		sl.SetStart(startTime),
		sl.SetEnd(time.Time{}),
	)

	if err := sdl.Collect(func(seq string, pkt []byte) (bool, error) {
		var record ms.Record
		err := record.Unpack(pkt)
		utils.CheckError(err)

		stationName := record.Station()
		data, err := record.Int32s()
		if err != nil {
			log.Warn().Str("station", stationName).Msg("Got invalid data from station, ignoring")
		} else {
			if _, ok := buffers[stationName]; !ok {
				buffers[stationName] = &[config.BufferSize]int32{}
				heads[stationName] = 0
				headLoops[stationName] = 0
				log.Info().Str("station", stationName).Str("url", url).Msg("Registered new station")
			}

			for i, datum := range data {
				buffers[stationName][(heads[stationName]+i)%config.BufferSize] = datum
			}
			heads[stationName] = (heads[stationName] + len(data)) % config.BufferSize
			headLoops[stationName] += (heads[stationName] + len(data)) / config.BufferSize
			if _, ok := stations.Stations[url]; ok {
				sampleRate := (*stations.Stations[url])[stationName].SampleRate
				if time.Since(startTime) > time.Duration((1e9*config.BufferSize)/float64(sampleRate)) {
					detected, pWaveArrival, sWaveArrival := detect.ThresholdDetectWaves(buffers[stationName], heads[stationName], "", false)
					if detected {
						timeOfPWaveArrival := startTime.Add(time.Duration(1e9 * float64(pWaveArrival) / float64((*stations.Stations[url])[stationName].SampleRate)))
						timeOfPWaveArrival = timeOfPWaveArrival.Add(time.Duration(1e9 * float64((headLoops[stationName]-1)*config.BufferSize) / float64(sampleRate)))

						timeOfSWaveArrival := startTime.Add(time.Duration(1e9 * float64(sWaveArrival) / float64((*stations.Stations[url])[stationName].SampleRate)))
						timeOfSWaveArrival = timeOfSWaveArrival.Add(time.Duration(1e9 * float64((headLoops[stationName]-1)*config.BufferSize) / float64(sampleRate)))

						if eventName, isNewEvent := events.NewDetection(url, stationName, timeOfPWaveArrival, timeOfSWaveArrival); isNewEvent {
							log.Info().
								Str("connection", url).
								Str("station", stationName).
								Int("pWaveArrival", pWaveArrival).
								Int("sWaveArrival", sWaveArrival).
								Msg("Detected wave arrival")
							detect.ThresholdDetectWaves(buffers[stationName], heads[stationName], eventName+"/"+url+"."+stationName, true)
						}
					}
				}
			}
		}
		return false, nil
	}); err != nil {
		log.Error().Err(err).Msg("Error collecting stream data")
	}
	select {}
}
